import jsbeautify from "js-beautify";
import format from "./format.js";
import path from "path";
import chalk from "chalk";
import fs from "fs";
import { RFile, GetJson, PathChoose, AskQuestions, AskOutPut } from "../util.js";

/**
 * 输出文件
 *
 * @param {String} filePath
 * @param {String} content
 */
const WriteFile = (filePath, content) => {
    fs.writeFile(path.resolve(filePath), content, "utf8", function (err) {
        if (err) {
            console.log(chalk.red(err));
        } else {
            console.log(chalk.greenBright(filePath + " : 输出成功!"));
        }
    });
};

/**
 * 导出文件
 *
 * @param {*} options
 * @param {*} config
 * @param {*} TypeStr
 * @param {*} ignore
 */
const ExportsFile = async (options, config, TypeStr, OutPut) => {
    var folder = SingleObjectFormat(options);
    var fileObject = renderSingleFile(folder, config, TypeStr);
    var filePath = OutPut + "/" + fileObject.key + ".js";
    WriteFile(filePath, fileObject.str);
};

/**
 * 格式化字符串
 *
 * @param {String} source
 * @return {*}
 */
const Beautify = (source) => {
    var opts = {};
    opts.indent_char = " ";
    opts.preserve_newlines = "-1";
    return jsbeautify.js(source, opts);
};

/**
 * 格式化树形结构
 *
 * @param {*} ele
 * @return {*}
 */
const SingleObjectFormat = (ele) => {
    var folder = {};
    folder.title = ele.info.title;
    folder.children = [];
    folder.models = {};
    folder.Schemas = {};
    var _models = ele.components.schemas;
    for (const key in _models) {
        const element = _models[key];
        folder.Schemas[key] = element;
        folder.models["#/components/schemas/" + key] = format.Models(element, key);
    }
    for (const url in ele.paths) {
        const method = ele.paths[url];
        for (const type in method) {
            const _file = method[type];
            var file = {};
            file.title = _file.summary;
            file.url = url;
            file.type = type;
            file.key = _file.tags[0];
            file.query = _file.parameters;
            _file.requestBody &&
                (() => {
                    file.body = {};
                    for (const key in _file.requestBody.content) {
                        const element = _file.requestBody.content[key];
                        if (key != "application/*+json" && key != "text/json" && key != "application/json-patch+json") {
                            file.body[key] = format.Models(element.schema, key);
                        }
                    }
                })();
            _file.responses &&
                (function () {
                    if (!_file.responses) {
                        return;
                    }
                    if (!_file.responses["200"]) {
                        return;
                    }
                    if (!_file.responses["200"].content) {
                        return;
                    }
                    if (!_file.responses["200"].content["application/json"]) {
                        return;
                    }
                    if (!_file.responses["200"].content["application/json"].schema) {
                        return;
                    }
                    file.responses = format.Models(_file.responses["200"].content["application/json"].schema, "200");
                })();
            folder.children.push(file);
        }
    }
    return folder;
};

/**
 * 文件夹格式化
 *
 * @param {*} folder
 * @param {*} config
 * @param {*} TypeStr
 * @return {*}
 */
const renderSingleFile = (folder, config, TypeStr) => {
    var key = "";
    var folderStrArray = [];
    var _nameKeys = [];
    // console.log(folder);

    folder.children.forEach((child) => {
        var $name = child.url.split("/");
        $name = $name.slice(3, $name.length).join("_");
        $name = $name.length ? $name : "root";
        key = child.key;

        if (_nameKeys.includes($name)) {
            $name += "_" + child.type;
        }

        _nameKeys.push($name);

        if (child.responses) {
            try {
                var _String = format.String(child.responses, folder.models);
                var _responses = "* // 返回值数据模型 \n" + "var responsesData = " + Beautify(_String) + "\n";
            } catch (error) {
                var _responses = "";
            }
        } else {
            var _responses = "// 无返回值数据";
        }

        var _bodyStr = "";
        var headers = {};
        for (const key in child.body) {
            const element = child.body[key];
            var _String = format.String(element, folder.models);
            _bodyStr += "* // Body参数 -- 类型 : " + key + "\n";
            _bodyStr += "var bodyData = " + Beautify(_String);
            if (key == "multipart/form-data") {
                headers["Content-Type"] = "multipart/form-data";
            }
        }

        const renderAnnotation = (item) => " // " + item.annotate + " (" + item.type + ") " + (item.checked ? "必填" : "") + "\n";
        var _queryString = "";
        var _queryArray = [];
        if (child.query) {
            child.query.forEach((ele) => {
                if (ele.in != "header") {
                    var _data = {};
                    _data.key = ele.name;
                    _data.type = ele.schema.type;
                    _data.annotate = ele.description || "";
                    _data.checked = !ele.nullable;
                    _queryArray.push(_data);
                }
            });

            if (_queryArray.length) {
                _queryString = "{";
                for (let i = 0; i < _queryArray.length; i++) {
                    var item = _queryArray[i];
                    if (item.type == "object") {
                        _queryString += item.key + ": {}," + renderAnnotation(item);
                    } else {
                        _queryString += (item.key ? item.key : "''") + ":" + "''," + renderAnnotation(item);
                    }
                }
                _queryString += "}";
                _queryString = Beautify(_queryString);
                _queryString = "* // url 参数 \n" + "var query =" + _queryString;
            }
        }
        // console.log(_queryString.replace(/\n/g, '\n \t* '));

        var str = `
    /**
    * ${child.title || child.url}
    *
    ${_queryString ? "* @param {Object} parmas Url参数" : ""}
    ${_bodyStr ? "* @param {Object} options Body参数" : ""}
    * @param {Blob} loading 是否显示loading
    * @return {Promise} 接口异步传输对象
    * @example 
    ${_queryString && _queryString.replace(/\n/g, "\n\t* ")}
    ${_bodyStr && _bodyStr.replace(/\n/g, "\n\t* ")}
    ${_responses && _responses.replace(/\n/g, "\n\t* ")}
    */
    '${$name}': function (${_queryString ? "parmas" : ""}${_bodyStr ? (_queryString ? ", options" : "options") : ""}${
            _queryString || _bodyStr ? ", loading" : "loading"
        }, header = ${JSON.stringify(headers)}) {
        return request.${child.type}('${child.url}', ${_queryString ? "parmas, " : "{}, "}${
            _bodyStr ? "options, " : "{}, "
        }'${TypeStr}', loading, header)
    },

`;
        folderStrArray.push(str);
    });
    var _str = config.formatModuleString || `import request from './request.js'\n`;
    _str += `\n\n// ${folder.title}\n`;
    _str += `export default {\n`;
    folderStrArray.forEach((ele) => {
        _str += "\t" + ele;
    });
    _str += "};";
    return {
        key: key,
        str: _str,
    };
};
export { ExportsFile }

export const Run = async (config) => {
    let DocPath = await PathChoose(config.path);
    const Doclist = await GetJson(DocPath._index);
    var QuestionsList = [];
    Doclist.forEach((ele) => {
        QuestionsList.push(ele.name + "(" + chalk.yellow(ele.key) + ")");
    });
    const answers = await AskQuestions(QuestionsList);
    if (answers._index == 0) {
        var requestList = [];
        Doclist.forEach((ele) => {
            requestList.push(RFile(ele.url));
        });
        var allDoc = await Promise.all(requestList);
        allDoc.forEach((ele) => {
            ExportsFile(ele, config, "", config.apiPath);
        });
    } else {
        var selectDoc = Doclist[answers._index - 1];
        var wrihteDoc = await RFile(selectDoc.url);
        ExportsFile(wrihteDoc, config, "", config.apiPath);
    }
};
